package com.xm.export.excel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.xm.export.excel.converter.Converter;
import com.xm.export.excel.converter.ConverterType;
import com.xm.export.excel.converter.DateConverter;
import com.xm.export.excel.converter.EnumConverter;
import com.xm.export.excel.converter.TextConverter;
import lombok.Getter;
import org.apache.commons.text.StringSubstitutor;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Getter
public class Exporter {
    private final ExcelType excelType;
    private final String sheetName;
    private final List<ColumnConfig> columnConfigList;
    private final List<Field> fieldList;

    public Exporter(String configStr) {
        JSONObject config = JSON.parseObject(configStr);
        this.sheetName = config.getString("sheetName");
        this.excelType = config.getObject("fileType", ExcelType.class);
        this.columnConfigList = config.getObject("columns", new TypeReference<List<ColumnConfig>>() {
        });

        JSONObject fields = config.getJSONObject("fields");
        this.fieldList = fields.entrySet().stream().map(e -> {
            Field field = new Field();
            field.setName(e.getKey());
            JSONArray converters = JSONArray.parseArray(e.getValue().toString());
            List<Converter> converterList = new ArrayList<>();
            for (int i = 0; i < converters.size(); i++) {
                JSONObject json = converters.getJSONObject(i);
                ConverterType type = json.getObject("type", ConverterType.class);
                if (type == ConverterType.text) {
                    converterList.add(new TextConverter(json.getString("expression")));
                } else if (type == ConverterType.date) {
                    converterList.add(new DateConverter(json.getString("from"), json.getString("pattern")));
                } else if (type == ConverterType.enums) {
                    HashMap<String, String[]> map = json.getObject("map", new TypeReference<HashMap<String, String[]>>() {
                    });
                    converterList.add(new EnumConverter(json.getString("from"), map));
                }
            }
            field.setConverterList(converterList);
            return field;
        }).collect(Collectors.toList());
    }


    /**
     * 导出
     *
     * @param dataList 数据列表
     * @return excel对象
     */
    public Workbook export(List<?> dataList) {

        Workbook wb;
        if (excelType == ExcelType.xls) {
            wb = new HSSFWorkbook();
        } else {
            wb = new XSSFWorkbook();
        }
        Sheet sheet = wb.createSheet(sheetName);

        //设置文本垂直和水平居中
        sheet.setHorizontallyCenter(true);
        sheet.setVerticallyCenter(true);

        //写入表头
        Row headRow = sheet.createRow(0);
        for (int i = 0; i < columnConfigList.size(); i++) {
            headRow.createCell(i).setCellValue(columnConfigList.get(i).getName());
        }
        List<Object> collect = dataList.stream().map(e -> {
            JSONObject target = (JSONObject) JSON.toJSON(e);
            fieldList.forEach(f -> f.invoke(target));
            return target;
        }).collect(Collectors.toList());


        //写入数据行
        for (int r = 1; r < dataList.size() + 1; r++) {
            Row row = sheet.createRow(r);
            //遍历列写入对应属性
            for (int c = 0; c < columnConfigList.size(); c++) {
                ColumnConfig columnConfig = columnConfigList.get(c);
                //创建单元格
                Cell cell = row.createCell(c);

                //获取对应行数据
                JSONObject target = (JSONObject) JSON.toJSON(collect.get(r - 1));
                StringSubstitutor sub = new StringSubstitutor(target);
                //写入数据
                cell.setCellValue(sub.replace(columnConfig.getValue()));
            }
        }
        return wb;
    }
}
